﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web;
using IEx.Common;
using IEx.Model.Partials;
using IEx.Model.Partials.Cuisine;
using IEx.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace IEx.ParserBuilder.RestaurantFoody
{
    public class FoodyParser : IHtmlParser
    {
        public void Parse(SourceItem item, string html, Action<Model.Partials.Announcement> attachResultItem, Action<SourceItem> attachNewItemSource)
        {
            try
            {
                string startHtml = "class=\"filter-results\"";
                string endHtml = "id=\"addWishListPopup\"";
                string remainHtml = Utility.GetHtmlBody(html, startHtml, endHtml);
                List<Announcement> detectedAnnouncements = new List<Announcement>();
                Uri newUri = Utility.CreateNewUriForNextPage(item.Url);
                bool hasData = true;

                if (!string.IsNullOrEmpty(remainHtml))
                {
                    string restaurantName = string.Empty;
                    string linkDetail = string.Empty;
                    string phone = string.Empty;
                    string address = string.Empty;
                    string description = string.Empty;
                    double point = double.MinValue;
                    RestaurantInfo restaurantInfo = new RestaurantInfo();

                    //Regex get data from Json
                    Regex dataRegex = new Regex(@"var jsonData\s*=\s*(\{.+?\});", RegexOptions.Multiline);
                    string extractedJson = dataRegex.Match(remainHtml).Result("$1");
                    JObject jsonData = JObject.Parse(extractedJson);
                    if (jsonData != null)
                    {
                        JToken allCuisines = jsonData["restaurants"];
                        if (allCuisines != null && allCuisines.HasValues)
                        {
                            JArray cuisinces = JArray.Parse(allCuisines.ToString());
                            foreach (var cuis in cuisinces)
                            {
                                //Special case when restaurant have never been rating
                                if (cuis["AvgRating"].ToString() == "\"--\"")
                                {
                                    cuis["AvgRating"] = 0;
                                }
                                CuisineInfo cuisItem = JsonConvert.DeserializeObject<CuisineInfo>(cuis.ToString());

                                if (cuisItem != null)
                                {
                                    Announcement ann = new Announcement();
                                    ann.InsertedDate = DateTime.Now;
                                    ann.Link = new Uri(newUri, cuisItem.DetailUrl).ToString();
                                    string des = cuisItem.SpecialDesc != null ? cuisItem.SpecialDesc : string.Empty;
                                    des = string.Join(string.Empty, Regex.Split(des, @"(?:\r\n\t|\n|\r|\t)"));
                                    ann.Message = RegexUtility.ExtractTextFromHtmlTag(HttpUtility.HtmlDecode(des));
                                    ann.SourceCode = item.SourceCode;
                                    ann.SocialNetwork.RestaurantInfo.Rate = cuisItem.AvgRating;
                                    ann.SocialNetwork.RestaurantInfo.ContactInfo.Address = cuisItem.Address + ", " + cuisItem.District + ", " + cuisItem.City;
                                    ann.SocialNetwork.RestaurantInfo.ContactInfo.HomePhone = cuisItem.Phone;
                                    ann.SourceId = item.SourceId;
                                    ann.Title = cuisItem.Name;
                                    detectedAnnouncements.Add(ann);
                                }
                            }
                        }
                        else
                        {
                            hasData = false;
                        }
                    }
                    Regex regNextPage = new Regex("class=\"load-more-result\">.*?</a>");
                    Match mNextPage = regNextPage.Match(remainHtml);
                    if (mNextPage.Success && hasData)
                    {
                        string nextPageHtml = mNextPage.Value.Trim();
                        string nextPageUrl = RegexUtility.ExtractHyperlink(nextPageHtml);
                        if (!string.IsNullOrEmpty(nextPageUrl))
                        {
                            item.Url = nextPageUrl;
                        }
                        else
                        {
                            item.Url = string.Empty;
                        }
                    }
                }
                // check if has next page 
                // next page counts as a new request, so it needed insert into request queue

                if (hasData)
                {
                    SourceItem nItem = new SourceItem(item.Url, item.LangId, item.SourceCode, item.SearchCode, item.SourceId, item.DateTimeFormat);
                    if (!string.IsNullOrEmpty(item.RequestBuilderType))
                        nItem.RequestBuilderType = item.RequestBuilderType;

                    if (!string.IsNullOrEmpty(item.HtmlParserType))
                        nItem.HtmlParserType = item.HtmlParserType;

                    nItem.PrevResponseHtml = html;
                    attachNewItemSource(nItem);
                }
                // insert into download queue when no error in parsing
                foreach (Announcement ann in detectedAnnouncements)
                {
                    attachResultItem(ann);
                }

                // if this request is fail request in previous scanning, 
                // remove it when success in current scanning
                if (item.FailId > 0)
                    Utility.DeleteFailRequests(item.FailId);
            }
            catch (Exception ex)
            {
                // if has an error, save fail request to next time scanning
                if (item.FailId == 0)
                {
                    item.FailId = DateTime.Now.Ticks;
                    Utility.SaveFailRequests(item);
                }

                // then write log
                string message = string.Format(@"
            Company code:   {0}
            HTML Parsing:   Fail
            Request URL:    {1}
            Search key:     {2}", item.SourceCode, item.Url, item.SearchCode);
                Logger.WriteError(message, ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <param name="item"></param>
        /// <param name="restaurantInfo"></param>
        private static void ExtractRestaurantFoodyDetails(string url, SourceItem item, ref RestaurantInfo restaurantInfo)
        {
        }
    }
}
